/**
 * @file clientprediction.h
 * @brief 客户端预测系统 - 提供即时响应和平滑游戏体验
 */

#ifndef CLIENTPREDICTION_H
#define CLIENTPREDICTION_H

#include <QObject>
#include <QPoint>
#include <QTimer>
#include <QQueue>
#include <QDateTime>

/**
 * @brief 客户端预测系统
 * 
 * 现代化游戏必备组件：
 * 1. 客户端预测：按键立即生效，无需等待服务器
 * 2. 服务器校正：收到服务器状态时进行校正
 * 3. 延迟补偿：根据网络延迟调整预测
 * 4. 平滑插值：在预测状态间进行平滑过渡
 */
class ClientPrediction : public QObject
{
    Q_OBJECT

public:
    explicit ClientPrediction(QObject *parent = nullptr);

    /**
     * @brief 输入命令结构
     */
    struct InputCommand {
        int direction;          // 方向 (0=UP, 1=DOWN, 2=LEFT, 3=RIGHT)
        qint64 timestamp;       // 命令时间戳
        int sequenceNumber;     // 序列号
        bool acknowledged;      // 是否已被服务器确认
    };

    /**
     * @brief 预测状态结构
     */
    struct PredictedState {
        QList<QPoint> snakeBody;    // 预测的蛇身体
        int direction;              // 当前方向
        qint64 timestamp;           // 状态时间戳
        int score;                  // 预测分数
        bool isValid;               // 状态是否有效
    };

public slots:
    /**
     * @brief 处理用户输入（立即预测）
     * @param direction 新方向
     */
    void handleUserInput(int direction);

    /**
     * @brief 接收服务器权威状态
     * @param serverState 服务器状态
     * @param serverTimestamp 服务器时间戳
     */
    void receiveServerState(const QList<QPoint> &snakeBody, int direction, 
                           qint64 serverTimestamp, int score);

    /**
     * @brief 设置网络延迟（用于延迟补偿）
     * @param latencyMs 延迟毫秒数
     */
    void setNetworkLatency(int latencyMs);

    /**
     * @brief 设置当前食物位置
     * @param foods 食物位置列表
     */
    void setCurrentFoods(const QList<QPoint> &foods);

    /**
     * @brief 启动/停止预测系统
     */
    void startPrediction();
    void stopPrediction();

    /**
     * @brief 设置地图配置
     * @param width 地图宽度
     * @param height 地图高度
     * @param enableWalls 是否启用墙壁碰撞
     */
    void setMapConfig(int width, int height, bool enableWalls);

    /**
     * @brief 获取当前预测状态
     * @return 当前预测状态
     */
    PredictedState getCurrentState() const;

    /**
     * @brief 执行一步预测
     * @param currentState 当前状态
     * @param direction 移动方向
     * @return 预测的下一状态
     */
    PredictedState predictNextState(const PredictedState &currentState, int direction);

signals:
    /**
     * @brief 预测状态更新信号
     * @param predictedState 预测的游戏状态
     */
    void predictedStateUpdated(const PredictedState &predictedState);

    /**
     * @brief 需要发送输入到服务器
     * @param direction 方向
     * @param sequenceNumber 序列号
     */
    void sendInputToServer(int direction, int sequenceNumber);

    /**
     * @brief 预测错误信号（需要校正）
     * @param errorMagnitude 错误程度
     */
    void predictionError(float errorMagnitude);

    /**
     * @brief 食物被吃信号
     * @param foodPosition 被吃的食物位置
     */
    void foodEaten(const QPoint &foodPosition);

private slots:
    /**
     * @brief 预测定时器回调（60FPS预测更新）
     */
    void onPredictionTick();

private:

    /**
     * @brief 校正预测状态
     * @param serverState 服务器权威状态
     */
    void reconcileWithServer(const PredictedState &serverState);

    /**
     * @brief 重新应用未确认的输入
     */
    void reapplyUnacknowledgedInputs();

    /**
     * @brief 计算状态差异
     * @param state1 状态1
     * @param state2 状态2
     * @return 差异程度 (0.0 = 完全相同, 1.0 = 完全不同)
     */
    float calculateStateDifference(const PredictedState &state1, const PredictedState &state2);

private:
    // === 预测系统核心 ===
    QTimer *m_predictionTimer;          // 60FPS预测定时器
    PredictedState m_currentState;      // 当前预测状态
    PredictedState m_lastServerState;   // 最后的服务器状态
    
    // === 输入管理 ===
    QQueue<InputCommand> m_inputHistory;    // 输入历史
    int m_nextSequenceNumber;               // 下一个序列号
    
    // === 网络补偿 ===
    int m_networkLatency;               // 网络延迟(ms)
    qint64 m_lastServerTimestamp;       // 最后服务器时间戳
    
    // === 预测参数 ===
    bool m_predictionEnabled;           // 是否启用预测
    float m_reconciliationThreshold;    // 校正阈值
    int m_maxInputHistory;              // 最大输入历史数量
    
    // === 性能统计 ===
    int m_predictionCount;              // 预测次数
    int m_correctionCount;              // 校正次数

    // === 地图配置 ===
    int m_mapWidth;                     // 地图宽度
    int m_mapHeight;                    // 地图高度
    bool m_enableWalls;                 // 是否启用墙壁碰撞
    float m_averageError;               // 平均预测误差

    // === 游戏数据 ===
    QList<QPoint> m_currentFoods;       // 当前食物位置
};

#endif // CLIENTPREDICTION_H
